#pragma once

enum SearchKbdKeys
{
  skk1,
  skk2,
  skk3,
  skk4,
  skk5,
  skk6,
  skk7,
  skk8,
  skk9,
  skkToggleMode,
  skkToggleLayout,
  skkBackspace,

  skkCount,
  skkNone
};

enum SearchKbdKeyState
{
  skksNormal    = 0x00,
  skksDisabled  = 0x01
};

enum SearchKbdMode
{
  skmNormal,
  skmMinimized
};

#define SKK_LETTER_KEYS_COUNT     9
#define SKK_ALPHABET_SEPARATOR    TEXT('%')
#define SKK_ALPHABET_INVISIBLE    TEXT('^')

#define SKK_BUTTONS_PER_ROW       3

#define SKK_ID_TEXT_LENGTH        5
#define SKK_LABEL_TEXT_LENGTH     6
#define SKK_MAX_STRING_LENGTH     128

#define SKK_TIMER_LAYOUT_DURATION 700

enum SearchAlphabetMode
{
  amPrimary,
  amSecondary
};

class SearchAlphabet
{
public:
  SearchAlphabet();
  SearchAlphabet(const TCHAR* szLetters);
  ~SearchAlphabet();

  bool   Create(const TCHAR* szLetters);

  const TCHAR* GetId() const;
  const TCHAR* GetLabel(SearchKbdKeys key) const;
  int    GetLabelLength(SearchKbdKeys key) const;
  TCHAR  GetInvisLabel(SearchKbdKeys key) const;
  bool   IsEmpty() const;

  TCHAR  LetterToKey(TCHAR l) const;
  bool   StringToKey(const TCHAR* str, TCHAR* keyStr, int maxLen) const;

  int    FindFilter(const TCHAR* str, const TCHAR* filter, int filterLen) const;
  int    FindText(const TCHAR* str, const TCHAR* text) const;

  int    FindWord(const TCHAR* str, const TCHAR* word) const;

private:
  TCHAR  id[SKK_ID_TEXT_LENGTH];
  TCHAR* letters;
  int*   keys;
  int    count;
  TCHAR  labels[SKK_LETTER_KEYS_COUNT][SKK_LABEL_TEXT_LENGTH];
  int    labelsLen[SKK_LETTER_KEYS_COUNT];
  TCHAR  invisLabels[SKK_LETTER_KEYS_COUNT];
};

class SearchAlphabetMgr
{
public:
  static bool Initialize();
  static void Terminate();

  static const SearchAlphabet& GetAlphabet();
  static bool  ToggleLayout();

  static const SearchAlphabet& GetPrimaryAlphabet();
  static const SearchAlphabet& GetSecondaryAlphabet();
  static bool  IsPrimarySelected();

  static TCHAR FilterToChar(SearchKbdKeys filter);
  static void  FilterToChars(const SearchKbdKeys* filter, int len, TCHAR* filterChars, int maxChars);

  static SearchKbdKeys CharToFilter(TCHAR c);

private:
  static SearchAlphabetMode s_AlphaMode;
  static SearchAlphabet s_Alpha1;
  static SearchAlphabet s_Alpha2;
};

class SearchKbd
{
public:
  SearchKbd(HWND hWnd, bool transparent);
  ~SearchKbd();

  void Close();

  void Reset();

  void Draw(HDC hdc, const RECT& rcClip);

  void OnMouseDown(int x, int y);
  void OnMouseMove(int x, int y);
  void OnMouseUp(int x, int y);

  void AddKey(SearchKbdKeys key);

  void SetRect(const RECT& rc);
  const RECT& GetRect() const
  { return s_Rect; }
  int GetWidth() const
  { return s_Rect.right - s_Rect.left; }
  int GetHeight() const
  { return s_Rect.bottom - s_Rect.top; }

  bool IsTransparent() const
  { return m_Mode == skmNormal && m_IsTransparent; }

  void ToggleMode();
  void SetMode(SearchKbdMode mode);
  SearchKbdMode GetMode() const
  { return m_Mode; }

  bool IsPtInRect(int x, int y) const;

  int  GetFilterLength()
  { return s_SearchStringLen; }

  void SetDisplayString(const TCHAR str[]);
  const TCHAR* GetDisplayString()
  { return s_SearchStringChars; }

protected:
  SearchKbdKeys PointToButton(int x, int y);
  void GetButtonRect(SearchKbdKeys key, RECT& rc);

  void SelectButton(SearchKbdKeys key);

  void MakeToggleLabel();

  static VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);

protected:
  HWND m_hWnd;
  int  m_BtnWidth;
  int  m_BtnHeight;
  int  m_SearchStrHeight;
  bool m_IsTransparent;

  SearchKbdMode m_Mode;
  SearchKbdKeys m_SelKey;

  int   m_KeyState[skkCount];

  bool  m_SkipMouseAction;
  TCHAR m_ToggleLabel[SKK_LABEL_TEXT_LENGTH];
  int   m_ToggleLabelLen;

  static RECT  s_Rect;
  static RECT  s_FullRect;
  static SearchKbdKeys s_SearchString[SKK_MAX_STRING_LENGTH];
  static int   s_SearchStringLen;
  static TCHAR s_SearchStringChars[SKK_MAX_STRING_LENGTH];
  static int   s_SearchStringCharsLen;

  static SearchKbd* s_pThis;
};

class ImeEditBox
{
public:
  ImeEditBox(int nId, HWND hwndParent, HINSTANCE hInst, bool show);
  ~ImeEditBox();

  void SetRect(const RECT& rc, bool redraw = false);
  
  LRESULT DoCtlColorEdit(HDC hdc);
  void DoBackspace();

  HWND GetWindow()
  { return m_hWnd; }

  void SetText(const TCHAR* szText);
  bool GetText(TCHAR* szText, int nSize);
  int  GetTextLength();

  void Show(int vKey = 0, bool setFocus = true);
  void Hide();

  bool IsVisible();

  void SetFocus();

private:
  static WNDPROC s_PrevWndProc;
  static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

private:
  HWND m_hWnd;
};